home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 151-175 / 169 / src / shell / execom.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  15KB  |  679 lines

  1.  
  2. /*
  3.  * EXECOM.C
  4.  *
  5.  * (c)1986 Matthew Dillon     9 October 1986
  6.  *
  7.  *    Handles command parsing.
  8.  *
  9.  *
  10.  */
  11.  
  12. #include "shell.h"
  13.  
  14. #define ST_COND   0x01
  15. #define ST_NAME   0x02
  16. #define ST_EXA      0x04        /*    exact match required    */
  17.  
  18.  
  19. struct COMMAND {
  20.     int (*func)();
  21.     short minargs;
  22.     short stat;
  23.     int   val;
  24.     char *name;
  25. };
  26.  
  27. extern char *format_insert_string();
  28. extern char *mpush(), *exarg();
  29.  
  30. extern int do_run(), do_number();
  31. extern int do_quit(), do_set_var(), do_unset_var(), do_setenv(), do_unsetenv();
  32. extern int do_printenv(), do_echo(), do_source(), do_mv();
  33. extern int do_cd(), do_rm(), do_mkdir(), do_history();
  34. extern int do_mem(), do_cat(), do_dir();
  35. extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
  36. extern int do_forever(), do_inc(), do_abortline();
  37. extern int do_input(), do_ver(), do_sleep(), do_help();
  38. extern int do_strhead(), do_strtail(), do_cp();
  39. extern int do_comment(), do_shellstat(), do_ipc(), do_cldres();
  40.  
  41. static struct COMMAND Command[] = {
  42.     do_run    , 0,  ST_NAME,      0 ,    "\001",
  43.     do_number    , 0,  0,      0 ,    "\001",
  44.     do_quit    , 0,  ST_EXA,      0 ,    "quit",
  45.     do_quit    , 0,  ST_EXA,      0 ,    "exit",
  46.     do_set_var    , 0,  0, LEVEL_SET  ,    "set",
  47.     do_unset_var, 0,  0, LEVEL_SET  ,    "unset",
  48.     do_setenv    , 2,  0,      0 ,    "setenv",
  49.     do_unsetenv , 0,  0,      0 ,    "unsetenv",
  50.     do_printenv , 0,  0,      0 ,    "printenv",
  51.     do_set_var    , 0,  0, LEVEL_ALIAS,    "alias",
  52.     do_unset_var, 0,  0, LEVEL_ALIAS,    "unalias",
  53.     do_echo    , 0,  0,      0 ,    "echo",
  54.     do_source    , 0,  0,      0 ,    "source",
  55.     do_mv    , 2,  ST_EXA,      0 ,    "mv",
  56.     do_cd    , 0,  0,      0 ,    "cd",
  57.     do_cd    , 0,  0,     -1 ,    "pwd",
  58.     do_rm    , 0,  ST_EXA,      0 ,    "rm",
  59.     do_mkdir    , 0,  ST_EXA,      0 ,    "mkdir",
  60.     do_history    , 0,  0,      0 ,    "history",
  61.     do_mem    , 0,  0,      0 ,    "mem",
  62.     do_cat    , 0,  0,      0 ,    "cat",
  63.     do_cp    , 1,  ST_EXA,      0 ,    "cp",
  64.     do_dir    , 0,  0,      0 ,    "dir",
  65.     do_dir    , 0,  0,     -1 ,    "devinfo",
  66.     do_foreach    , 3,  0,      0 ,    "foreach",
  67.     do_forever    , 1,  0,      0 ,    "forever",
  68.     do_return    , 0,  ST_EXA,      0 ,    "return",
  69.     do_ipc    , 1,  0,      0 ,    "ipc",
  70.     do_cldres    , 0,  0,      0 ,    "cldres",
  71.     do_if    , 1,  ST_COND,      0 ,    "if",
  72.     do_if    , 0,  ST_COND,      1 ,    "else",
  73.     do_if    , 0,  ST_COND,      2 ,    "endif",
  74.     do_label    , 1,  ST_COND,      0 ,    "label",
  75.     do_goto    , 1,  0,      0 ,    "goto",
  76.     do_strhead    , 3,  0,      0 ,    "strhead",
  77.     do_strtail    , 3,  0,      0 ,    "strtail",
  78.     do_inc    , 1,  0,      1 ,    "inc",
  79.     do_inc    , 1,  0,      -1,    "dec",
  80.     do_input    , 1,  0,      0,    "input",
  81.     do_ver    , 0,  0,      0,    "version",
  82.     do_sleep    , 0,  0,      0,    "sleep",
  83.     do_help    , 0,  0,      0,    "help",
  84.     do_abortline, 0,  0,      0,    "abortline",
  85.     do_comment    , 2,  0,      0,    "comment",
  86.     do_shellstat, 0,  0,      0,    "shellstat",
  87.     NULL    , 0,  0,      0 ,    NULL
  88. };
  89.  
  90.  
  91. static unsigned char elast;         /* last end delimeter */
  92. static char Cin_ispipe, Cout_ispipe;
  93.  
  94. exec_command(base)
  95. char *base;
  96. {
  97.     register char *scr;
  98.     register int i;
  99.     char buf[32];
  100.  
  101.     if (!H_stack) {
  102.     add_history(base);
  103.     sprintf(buf, "%ld", H_tail_base + H_len);
  104.     set_var(LEVEL_SET, V_HISTNUM, buf);
  105.     }
  106.     scr = malloc((strlen(base) << 2) + 2);    /* 4X */
  107.     preformat(base, scr);
  108.     i = fcomm(scr, 1);
  109.     return ((i) ? -1 : 1);
  110. }
  111.  
  112.  
  113. isalphanum(c)
  114. char c;
  115. {
  116.     if (c >= '0' && c <= '9')
  117.     return (1);
  118.     if (c >= 'a' && c <= 'z')
  119.     return (1);
  120.     if (c >= 'A' && c <= 'Z')
  121.     return (1);
  122.     if (c == '_')
  123.     return (1);
  124.     return (0);
  125. }
  126.  
  127. preformat(s, d)
  128. register char *s, *d;
  129. {
  130.     register short si, di, qm;
  131.  
  132.     si = di = qm = 0;
  133.     while (s[si] == ' ' || s[si] == 9)
  134.     ++si;
  135.     while (s[si]) {
  136.     if (qm && s[si] != '\"' && s[si] != '\\') {
  137.         d[di++] = s[si++] | 0x80;
  138.         continue;
  139.     }
  140.     switch (s[si]) {
  141.     case ' ':
  142.     case 9:
  143.         d[di++] = ' ';
  144.         while (s[si] == ' ' || s[si] == 9)
  145.         ++si;
  146.         if (s[si] == 0 || s[si] == '|' || s[si] == ';')
  147.         --di;
  148.         break;
  149.     case '*':
  150.     case '?':
  151.         d[di++] = 0x80;     /* follow thru */
  152.     case '!':
  153.         d[di++] = s[si++];
  154.         break;
  155.     case '#':
  156.         d[di++] = '\0';
  157.         while (s[si])
  158.         ++si;
  159.         break;
  160.     case ';':
  161.     case '|':
  162.         d[di++] = s[si++];
  163.         while (s[si] == ' ' || s[si] == 9)
  164.         ++si;
  165.         break;
  166.     case '\\':
  167.         d[di++] = s[++si] | 0x80;
  168.         if (s[si]) ++si;
  169.         break;
  170.     case '\"':
  171.         qm = 1 - qm;
  172.         ++si;
  173.         break;
  174.     case '^':
  175.         d[di++] = s[++si] & 0x1F;
  176.         if (s[si]) ++si;
  177.         break;
  178.     case '$':         /* search end of var name and place false space */
  179.         d[di++] = 0x80;
  180.         d[di++] = s[si++];
  181.         while (isalphanum(s[si]))
  182.         d[di++] = s[si++];
  183.         d[di++] = 0x80;
  184.         break;
  185.     default:
  186.         d[di++] = s[si++];
  187.         break;
  188.     }
  189.     }
  190.     d[di++] = 0;
  191.     d[di]   = 0;
  192. #ifdef DEBUG
  193.     if (SDebug & 0x01) {
  194.     fhprintf (Cerr, "PREFORMAT: %ld :%s:\n", strlen(d), d);
  195.     }
  196. #endif
  197. }
  198.  
  199. /*
  200.  * process formatted string.  ' ' is the delimeter.
  201.  *
  202.  *    0: check '\0': no more, stop, done.
  203.  *    1: check $.     if so, extract, format, insert
  204.  *    2: check alias. if so, extract, format, insert. goto 1
  205.  *    3: check history or substitution, extract, format, insert. goto 1
  206.  *
  207.  *    4: assume first element now internal or disk based command.
  208.  *
  209.  *    5: extract each ' ' or 0x80 delimited argument and process, placing
  210.  *     in av[] list (except 0x80 args appended).  check in order:
  211.  *
  212.  *           '$'         insert string straight
  213.  *           '>'         setup stdout
  214.  *           '>>'        setup stdout flag for append
  215.  *           '<'         setup stdin
  216.  *           '*' or '?'  do directory search and insert as separate args.
  217.  *
  218.  *           ';' 0 '|'   end of command.  if '|' setup stdout
  219.  *                -execute command, fix stdin and out (|) sets
  220.  *                 up stdin for next guy.
  221.  */
  222.  
  223.  
  224. fcomm(str, freeok)
  225. register char *str;
  226. {
  227.     static short alias_count;
  228.     char *istr;
  229.     char *nextstr;
  230.     char *command;
  231.     char *pend_alias = NULL;
  232.     char err = 0;
  233.  
  234.     ++alias_count;
  235.     mpush_base();
  236.     if (*str == 0)
  237.     goto done1;
  238. step1:
  239.     if (alias_count == MAXALIAS) {
  240.     Eputs("Alias Loop");
  241.     err = 20;
  242.     goto done1;
  243.     }
  244.     if (*str == '$') {
  245.     if (istr = get_var (LEVEL_SET, str + 1))
  246.         str = format_insert_string(str, istr, &freeok);
  247.     }
  248.     istr = NULL;
  249.     if (*(unsigned char *)str < 0x80)
  250.     istr = get_var (LEVEL_ALIAS, str);  /* only if not \command */
  251.     *str &= 0x7F;               /* remove \ teltail       */
  252.     if (istr) {
  253.     if (*istr == '%') {
  254.         pend_alias = istr;
  255.     } else {
  256.         str = format_insert_string(str, istr, &freeok);
  257.         goto step1;
  258.     }
  259.     }
  260.     if (*str == '!') {
  261.     istr = get_history(str);
  262.     replace_head(istr);
  263.     str = format_insert_string(str, istr, &freeok);
  264.     goto step1;
  265.     }
  266.     nextstr = str;
  267.     command = exarg(&nextstr);
  268.     if (*command == 0)
  269.     goto done0;
  270.     if (pend_alias == 0) {
  271.     register int ccno;
  272.     ccno = find_command(command);
  273.     if (Command[ccno].stat & ST_COND)
  274.         goto skipgood;
  275.     }
  276.     if (SDisable) {
  277.     while (elast && elast != ';' && elast != '|')
  278.         exarg(&nextstr);
  279.     goto done0;
  280.     }
  281. skipgood:
  282.     {
  283.     register char *arg, *ptr, *scr;
  284.     short redir;
  285.     short doexpand;
  286.     short cont;
  287.     short inc;
  288.  
  289.     ac = 1;
  290.     av[0] = command;
  291. step5:                        /* ac = nextac */
  292.     if (!elast || elast == ';' || elast == '|')
  293.         goto stepdone;
  294.  
  295.     av[ac] = NULL;
  296.     cont = 1;
  297.     doexpand = redir = inc = 0;
  298.  
  299.     while (cont && elast) {
  300.         ptr = exarg(&nextstr);
  301.         inc = 1;
  302.         arg = "";
  303.         cont = (elast == 0x80);
  304.         switch (*ptr) {
  305.         case '<':
  306.         redir = -2;         /* -2 so ++ still keeps it negative */
  307.         case '>':
  308.         ++redir;         /* normal >  */
  309.         arg = ptr + 1;
  310.         if (*arg == '>') {
  311.             redir = 2;          /* append >> (not impl yet) */
  312.             ++arg;
  313.         }
  314.         cont = 1;
  315.         break;
  316.         case '$':
  317.         if ((arg = get_var(LEVEL_SET, ptr + 1)) == NULL)
  318.             arg = ptr;
  319.         break;
  320.          case '*':
  321.          case '?':
  322.         doexpand = 1;
  323.         arg = ptr;
  324.         break;
  325.         default:
  326.         arg = ptr;
  327.         break;
  328.         }
  329.  
  330.         /* Append arg to av[ac] */
  331.  
  332.         for (scr = arg; *scr; ++scr)
  333.         *scr &= 0x7F;
  334.         if (av[ac]) {
  335.         register char *old = av[ac];
  336.         av[ac] = mpush(strlen(arg)+1+strlen(av[ac]));
  337.         strcpy(av[ac], old);
  338.         strcat(av[ac], arg);
  339.         } else {
  340.         av[ac] = mpush(strlen(arg)+1);
  341.         strcpy(av[ac], arg);
  342.         }
  343.         if (elast != 0x80)
  344.         break;
  345.     }
  346.  
  347.     /* process expansion */
  348.  
  349.     if (doexpand) {
  350.         char **eav, **ebase;
  351.         int eac;
  352.  
  353.         eav = ebase = expand(av[ac], &eac);
  354.         inc = 0;
  355.         if (eav) {
  356.         if (ac + eac + 2 > MAXAV) {
  357.             ierror (NULL, 506);
  358.             err = 1;
  359.         } else {
  360.             QuickSort(eav, eac);
  361.             for (; eac; --eac, ++eav)
  362.             av[ac++] = strcpy(mpush(strlen(*eav)+1), *eav);
  363.         }
  364.         free_expand (ebase);
  365.         }
  366.     }
  367.  
  368.     /* process redirection    */
  369.  
  370.     if (redir && !err) {
  371.         register char *file = (doexpand) ? av[--ac] : av[ac];
  372.  
  373.         if (redir < 0) {
  374.         Cin_name = file;
  375.         } else {
  376.         Cout_name = file;
  377.         Cout_append = (redir == 2);
  378.         }
  379.         inc = 0;
  380.     }
  381.  
  382.     /* check elast for space */
  383.  
  384.     if (inc) {
  385.         ++ac;
  386.         if (ac + 2 > MAXAV) {
  387.         ierror (NULL, 506);
  388.         err = 1;        /* error condition */
  389.         elast = 0;        /* don't process any more arguemnts */
  390.         }
  391.     }
  392.     if (elast == ' ')
  393.         goto step5;
  394.     }
  395. stepdone:
  396.     av[ac] = NULL;
  397.  
  398.     /* process pipes via files */
  399.  
  400.     if (elast == '|' && !err) {
  401.     static int which;          /* 0 or 1 in case of multiple pipes */
  402.     which = 1 - which;
  403.     Cout_name = (which) ? Pipe1 : Pipe2;
  404.     Cout_ispipe = 1;
  405.     }
  406.  
  407.     if (err)
  408.     goto done0;
  409.  
  410.     {
  411.     register long i, len;
  412.     char save_elast;
  413.     register char *avline;
  414.  
  415.     save_elast = elast;
  416.     for (i = len = 0; i < ac; ++i)
  417.         len += strlen(av[i]) + 1;
  418.     avline = malloc(len+2);
  419.     for (len = 0, i = ((pend_alias) ? 1 : 0); i < ac; ++i) {
  420. #ifdef DEBUG
  421.         if (SDebug & 0x02) fhprintf (Cerr, "AV[%2ld] %ld :%s:\n", i, strlen(av[i]), av[i]);
  422. #endif
  423.         strcpy(avline + len, av[i]);
  424.         len += strlen(av[i]);
  425.         if (i + 1 < ac)
  426.         avline[len++] = ' ';
  427.     }
  428.     avline[len] = 0;
  429.     if (pend_alias) {                               /* special % alias */
  430.         register char *ptr, *scr;
  431.         for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
  432.         set_var (LEVEL_SET, pend_alias + 1, avline);
  433.         free (avline);
  434.         scr = malloc((strlen(ptr) << 2) + 2);
  435.         preformat (ptr, scr);
  436.         fcomm (scr, 1);
  437.         unset_var (LEVEL_SET, pend_alias + 1);
  438.     } else {                    /* normal command  */
  439.         register short ccno;
  440.         register long cin, cout;
  441.  
  442.         ccno = find_command (command);
  443.         if ((Command[ccno].stat & ST_NAME) == 0) {
  444.         if (Cin_name) {
  445.             cin = Cin;
  446.             Cin = Open(Cin_name, 1005);
  447.             if (Cin == 0) {
  448.             ierror (NULL, 504);
  449.             err = 1;
  450.             Cin = cin;
  451.             Cin_name = NULL;
  452.             }
  453.         }
  454.         if (Cout_name) {
  455.             cout = Cout;
  456.             if (Cout_append) {
  457.             if (Cout = Open(Cout_name, 1005))
  458.             Seek(Cout, 0, 1);
  459.             } else {
  460.             Cout = Open(Cout_name, 1006);
  461.             }
  462.             if (Cout == NULL) {
  463.             err = 1;
  464.             ierror (NULL, 504);
  465.             Cout = cout;
  466.             Cout_name = NULL;
  467.             Cout_append = 0;
  468.             }
  469.         }
  470.         }
  471.         if (ac < Command[ccno].minargs + 1) {
  472.         ierror (NULL, 500);
  473.         err = -1;
  474.         } else {
  475.         i = (*Command[ccno].func)(avline, Command[ccno].val);
  476.         if (i < 0)
  477.             i = 20;
  478.         err = i;
  479.         }
  480.         free (avline);
  481.         if (Exec_ignoreresult == 0 && Lastresult != err) {
  482.         Lastresult = err;
  483.         seterr();
  484.         }
  485.         if ((Command[ccno].stat & ST_NAME) == 0) {
  486.         if (Cin_name) {
  487.             Close(Cin);
  488.             Cin = cin;
  489.         }
  490.         if (Cout_name) {
  491.             Close(Cout);
  492.             Cout = cout;
  493.             Cout_append = 0;
  494.         }
  495.         }
  496.     }
  497.     if (Cin_ispipe && Cin_name)
  498.         DeleteFile(Cin_name);
  499.     if (Cout_ispipe) {
  500.         Cin_name = Cout_name;      /* ok to assign.. static name */
  501.         Cin_ispipe = 1;
  502.     } else {
  503.         Cin_name = NULL;
  504.     }
  505.     Cout_name = NULL;
  506.     Cout_ispipe = Cout_append = 0;
  507.     elast = save_elast;
  508.     }
  509.     mpop_tobase();                      /* free arguments   */
  510.     mpush_base();                       /* push dummy base  */
  511.  
  512. done0:
  513.     {
  514.     register char *str;
  515. #ifdef DEBUG
  516.     if (SDebug & 0x10)
  517.         printf ("err = %ld, E_stack = %ld\n", err, E_stack);
  518. #endif
  519.     if (err && E_stack == 0) {
  520.         str = get_var(LEVEL_SET, V_EXCEPT);
  521.         if (err >= ((str)?atoi(str):1)) {
  522.         if (str) {
  523.             ++H_stack;
  524.             ++E_stack;
  525.             exec_command(str);
  526.             --E_stack;
  527.             --H_stack;
  528.         } else {
  529.           Exec_abortline = 1;
  530.         }
  531.         }
  532.     }
  533. #ifdef DEBUG
  534.     if (SDebug & 0x10) {
  535.         printf ("elast = %ld  Exec_abortline = %ld\n", elast, Exec_abortline);
  536.         printf ("nextstr = %s\n", nextstr);
  537.     }
  538. #endif
  539.     if (elast != 0 && Exec_abortline == 0)
  540.         err = fcomm(nextstr, 0);
  541.     Exec_abortline = 0;
  542.     if (Cin_name)
  543.         DeleteFile(Cin_name);
  544.     Cin_name = NULL;
  545.     Cin_ispipe = 0;
  546.     }
  547. done1:
  548.     mpop_tobase();
  549.     if (freeok)
  550.     free(str);
  551.     --alias_count;
  552.     return ((int)err);                  /* TRUE = error occured    */
  553. }
  554.  
  555.  
  556. char *
  557. exarg(ptr)
  558. unsigned char **ptr;
  559. {
  560.     register unsigned char *end;
  561.     register unsigned char *start;
  562.  
  563.     start = end = *ptr;
  564.     while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
  565.     ++end;
  566.     elast = *end;
  567.     *end = '\0';
  568.     *ptr = end + 1;
  569.     return ((char *)start);
  570. }
  571.  
  572. static char **Mlist;
  573.  
  574. mpush_base()
  575. {
  576.     register char *str;
  577.  
  578.     str = malloc(5);
  579.     *(char ***)str = Mlist;
  580.     str[4] = 0;
  581.     Mlist = (char **)str;
  582. }
  583.  
  584. char *
  585. mpush(bytes)
  586. {
  587.     register char *str;
  588.  
  589.     str = malloc(5 + bytes);
  590.     *(char ***)str = Mlist;
  591.     str[4] = 1;
  592.     Mlist = (char **)str;
  593.     return (str + 5);
  594. }
  595.  
  596. mpop_tobase()
  597. {
  598.     register char *next;
  599.  
  600.     while (Mlist) {
  601.     next = *Mlist;
  602.     if (((char *)Mlist)[4] == 0) {
  603.         free (Mlist);
  604.         Mlist = (char **)next;
  605.         break;
  606.     }
  607.     free (Mlist);
  608.     Mlist = (char **)next;
  609.     }
  610. }
  611.  
  612.  
  613. /*
  614.  * Insert 'from' string in front of 'str' while deleting the
  615.  * first entry in 'str'.  if freeok is set, then 'str' will be
  616.  * free'd
  617.  */
  618.  
  619. char *
  620. format_insert_string(str, from, freeok)
  621. char *str;
  622. char *from;
  623. int *freeok;
  624. {
  625.     register char *new1, *new2;
  626.     register unsigned char *strskip;
  627.     register short len;
  628.  
  629.     for (strskip = (UBYTE *)str; *strskip && *strskip != ' ' && *strskip != ';' && *strskip != '|' && *strskip != 0x80; ++strskip);
  630.     len = strlen(from);
  631.     new1 = malloc((len << 2) + 2);
  632.     preformat(from, new1);
  633.     len = strlen(new1) + strlen(strskip);
  634.     new2 = malloc(len+2);
  635.     strcpy(new2, new1);
  636.     strcat(new2, strskip);
  637.     new2[len+1] = 0;
  638.     free (new1);
  639.     if (*freeok)
  640.     free (str);
  641.     *freeok = 1;
  642.     return (new2);
  643. }
  644.  
  645.  
  646. find_command(str)
  647. register char *str;
  648. {
  649.     register short i;
  650.     register short len = strlen(str);
  651.     register struct COMMAND *cmd;
  652.  
  653.     if (*str >= '0'  &&  *str <= '9')
  654.     return (1);
  655.     for (i = 0, cmd = Command; cmd->func; ++cmd, ++i) {
  656.     if (cmd->stat & ST_EXA) {
  657.         if (strcmp(str, cmd->name) == 0)
  658.         return((int)i);
  659.     } else {
  660.         if (strncmp (str, cmd->name, len) == 0)
  661.         return ((int)i);
  662.     }
  663.     }
  664.     return (0);
  665. }
  666.  
  667.  
  668. do_help()
  669. {
  670.     register struct COMMAND *com;
  671.  
  672.     for (com = &Command[2]; com->func; ++com)
  673.     fhprintf (Cout, "%s ", com->name);
  674.     Oputs ("");
  675.     return (0);
  676. }
  677.  
  678.  
  679.